/**
 * @author Jerry
 */

//sudoku size
var size = 9;

//value of each cell box
var sudoku_element = new Array(size);
var sudoku_element_copy = new Array(size);
for(var i = 0; i < size; i++) {
    sudoku_element[i] = new Array(size);
    sudoku_element_copy[i] = new Array(size);
}

//the status of each element, 1 means the element is a input from user
var element_status = new Array(size);
for(var i = 0; i < size; i++){
    element_status[i] = new Array(size);
}

//the value of each cell and the status are initialized to 0
for(var i = 0; i < size; i++) {
    for(var j = 0; j < size; j++) {
        sudoku_element[i][j] = 0;
        element_status[i][j] = 0;
    }
}

//3-D array to store available numbers for each cell
//each cell is initialized to 0
var availableNum = new Array(size);
for(var i = 0; i < size; i++) {
    availableNum[i] = new Array(size);
    for(var j = 0; j < size; j++) {
        availableNum[i][j] = new Array(size);
        for(var k = 0; k < size; k++) {
            availableNum[i][j][k] = 0;
        }
    }
}

//board stored in a string
var board = '<table>';

//create the sudoku game board
function buildBoard() {
    for(var i = 0; i < size; i++) {
        board = board + '<tr>';
        for(var j = 0; j < size; j++) {
            if((i < 3 && (j < 3 || j > 5)) || ((i > 2 && i < 6) && (j > 2 && j < 6)) || (i > 5 && (j < 3 || j > 5))) {
                board += '<td id = "cell_' + i + '_' + j + '" rowNum = "' + i + '" colNum = "' + j + '" class = "cell_gray">';
                board += '</td>';
                continue;
            } else {
                board += '<td id = "cell_' + i + '_' + j + '" rowNum = "' + i + '" colNum = "' + j + '" class = "cell_white">';
                board += '</td>';
                continue;
            }
        }
        board = board + '</tr>';
    }
    board += '</table>';
}

buildBoard();
//document.write(board);
var sudoku_frame = document.getElementById('sudoku');
sudoku_frame.className = 'sudoku_board';
sudoku_frame.innerHTML = board;
sudoku_frame.onclick = function(e) {
    var target = e.target;
    if(target.className == "cell_gray" || target.className == "cell_white") {
        var i = parseInt(target.getAttribute('rowNum'));
        var j = parseInt(target.getAttribute('colNum'));
        console.log('box', i, j);
        var temp = prompt("give a value");
        if(temp > 0 && temp <= 9) {
            sudoku_element[i][j] = parseInt(temp);
            element_status[i][j] = 1;
            target.style.color = 'red';
            target.innerHTML = temp;
            console.log(sudoku_element[i][j]);
        } else {
            alert("Please type in a digit between 0-9");
        }
    }
}
//create a solve button
var solve_button = document.createElement('input');
solve_button.type = 'button';
solve_button.value = 'solve';
solve_button.className = 'solve';
solve_button.onclick = function() {
    solver();
    print_sudoku();
    //alert("this is a debug");
}
//create a reset button
var reset_button = document.createElement('input');
reset_button.type = 'button';
reset_button.value = 'reset';
reset_button.className = 'reset_button';
reset_button.onclick = function() {
    reset();
    //print_sudoku();
}

sudoku_frame.appendChild(solve_button);
sudoku_frame.appendChild(reset_button);
document.body.appendChild(sudoku_frame);
//var change = document.getElementById('cell_0_0');
//change.innerHTML = "this is a test.";

var level = "<input type='radio' name ='level'>easy<br/>"
            + "<input type='radio' name='level'>medium<br/>"
            + "<input type='radio' name='level'>hard<br/>";
var start = document.createElement('input');
start.type = 'button';
start.value = 'start';
start.onclick = function() {
    start_sudoku();
}

//build side board
var side_board = document.createElement('div');
side_board.className = 'side_board';
side_board.innerHTML = level;
side_board.appendChild(start);
document.body.appendChild(side_board);

//sudoku solve function
function solver() {
    var m = 0, n = 0;
    while(m < size && n < size) {
        var i, j;
        for( i = 0; i < size; i++) {
            for( j = 0; j < size; j++) {
                if(sudoku_element[i][j] == 0) {
                    break;
                }
            }
            if(j < size - 1) {
                break;
            } else if(sudoku_element[i][j] == 0) {
                break;
            }
        }
        if(i == 8 && j == 8 && sudoku_element[i][j] != 0) {
            return;
        }
        m = i;
        n = j;
        if(i < size && j < size) {
            check(i, j);

            var count;
            for( count = 0; count < size; count++) {
                if(availableNum[i][j][count] == 0) {
                    //sudoku_element[i][j] = count + 1;
                    break;
                }
            }
            if(count < size) {
                var random_choice = new Array(9);
                for(var k = 0; k < size; k++) {
                    random_choice[k] = 0;
                }
                var pos = 0;
                for(var k = 0; k < size; k++) {
                    if(availableNum[i][j][k] == 0) {
                        random_choice[pos] = k + 1;
                        pos++;
                    }
                }
                var random_pos = Math.floor(Math.random() * pos);
                sudoku_element[i][j] = random_choice[random_pos];
            } else if(count == size) {
                if(j == 0) {
                    availableNum[i - 1][size - 1][sudoku_element[i - 1][size - 1] - 1] = -1;
                    sudoku_element[i - 1][size - 1] = 0;
                    for(var k = 0; k < size; k++) {
                        availableNum[i][j][k] = 0;
                    }
                } else {
                    var cMove = j - 1;
                    var rMove = i;
                    while(element_status[(rMove % size)][(cMove % size)] == 1){
                        cMove--;
                        if(cMove < 0){
                            cMove = size - 1;
                            rMove = rMove - 1;
                        }
                        if(rMove < 0){
                            alert("No Solution. Please reset the board");
                            return;
                        }
                    }
                    availableNum[rMove][cMove][sudoku_element[rMove][cMove] - 1] = -1;
                    sudoku_element[rMove][cMove] = 0;
                    for(var k = 0; k < size; k++) {
                        availableNum[i][j][k] = 0;
                    }

                }
            }
        } else {
            return;
        }
    }
}

//check number availability for each cell
function check(row, col) {
    if(sudoku_element[row][col] >= 0) {
        //check for the number availability in the same row
        for(var count = 0; count < size; count++) {
            if(count == col) {
                continue;
            }
            if(sudoku_element[row][count] > 0 && availableNum[row][col][sudoku_element[row][count] - 1] == 0) {
                availableNum[row][col][sudoku_element[row][count] - 1] = 1;
            }
        }

        //check for the number availability in the same column
        for(var count = 0; count < size; count++) {
            if(count == row) {
                continue;
            }
            if(sudoku_element[count][col] > 0 && availableNum[row][col][sudoku_element[count][col] - 1] == 0) {
                availableNum[row][col][sudoku_element[count][col] - 1] = 1;
            }
        }

        //check for the number availability in the same sub board
        var subboard_size = size / 3;
        var rStart = Math.floor(row / subboard_size);
        var cStart = Math.floor(col / subboard_size);
        var rTimes = 0;
        var cTimes = 0;
        for(var rCount = rStart * subboard_size; rTimes < subboard_size; rCount++, rTimes++) {
            for(var cCount = cStart * subboard_size; cTimes < subboard_size; cCount++, cTimes++) {
                if(rCount == row && cCount == col) {
                    continue;
                }
                if(sudoku_element[rCount][cCount] > 0 && availableNum[row][col][sudoku_element[rCount][cCount] - 1] == 0) {
                    availableNum[row][col][sudoku_element[rCount][cCount] - 1] = 1;
                }
            }
            cTimes = 0;
        }
    }
}

//print the sudoku result on to the board
function print_sudoku() {
    for(var i = 0; i < size; i++) {
        for(var j = 0; j < size; j++) {
            var change_cell = document.getElementById('cell_' + i + '_' + j + '');
            change_cell.innerHTML = sudoku_element[i][j];
        }
    }
}

//reset the sudoku
function reset() {
    for(var i = 0; i < size; i++) {
        for(var j = 0; j < size; j++) {
            sudoku_element[i][j] = 0;
            var cell_target = document.getElementById('cell_' + i + '_' + j + '');
            cell_target.innerHTML = "";
            cell_target.style.color = 'black';
            for(var k = 0; k < size; k++) {
                sudoku_element[i][j][k] = 0;
            }
        }
    }
}

//start the sudoku game
function start_sudoku() {
    solver();
    sudoku_element_copy = sudoku_element;
    
}

//get the level of hardness
function get_level() {
    var lv = document.getElementsByName('level');
    for(var i = 0; i < lv.length; i++) {
        if(lv[i].checked) {
            return i;
        }
    }
}

//check for the number of only one solution
function one_solution_count() {
    var counter = 0;
    var total_count = 0;
    for(var i = 0; i < size; i++) {
        for(var j = 0; j < size; j++) {
          for(var k = 0; k < size; k++) {
            if(availableNum[i][j][k] == 0) {
                counter++;
            }
          }
          if(counter == 1) {
            total_count++;
          }
          counter = 0;  
        }
    }
    return total_count;
}